package com.ucs.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.content.Context;
import android.os.Handler;
import android.util.Log;
import android.widget.ArrayAdapter;

import com.ucs.domain.Category;
import com.ucs.domain.Item;
import com.ucs.domain.Order;
import com.ucs.domain.User;
import com.ucs.ui.OrderListAdaptor;

public class UCSData {
	private static final String SERVERNAME_XML="server.xml";
	private static final String USERS_XML = "users.xml";
	private static final String CATEGORIES_XML = "categories.xml";
	private static final String PENDING_ORDERS_XML = "pending_orders.xml";
	private static final String TAG="ucs";
	private Context signinContext = null;

	private static UCSData instance=new UCSData();
	
	private List<Order> pendingOrderList = null;
//	private Context mainActionContext;
	private ArrayAdapter<String> mainActionsAdapter = null;
	private OrderListAdaptor pendingOrderListAdaptor = null;
	
	synchronized public static UCSData getInstance(){
		return instance;
	}
		
//	public void printPendingOrderList(){
//		for (Order order : pendingOrderList) {
//			Log.d("ucs", "table="+order.getTableID()+", no_of_items="+order.getOrderDetails().size());
//		}
//	}
	public OrderListAdaptor getPendingOrderListAdaptor(Context context){
		if (pendingOrderListAdaptor == null){
			pendingOrderListAdaptor = new OrderListAdaptor(context, pendingOrderList);
		}
		return pendingOrderListAdaptor;
	}
	
	public void postAPendingOrder(){
		if (pendingOrderList.size() == 0){
			return;
		}
		
	}

	private static ArrayAdapter<Integer> guestsAdapter = null;
	public ArrayAdapter<Integer> getGuestsAdapter(Context context){
		if (guestsAdapter == null){
			List<Integer> guestsList = new ArrayList<Integer>();
			for (int i=0; i<100; ++i){
				guestsList.add(i+1);
			}
			guestsAdapter = new ArrayAdapter<Integer>(context, android.R.layout.simple_list_item_1, guestsList);
		}
		return guestsAdapter;
	}
	
	private static String[] actions = {"Create Order", "Review Open Orders", "Review Pending Orders"};
	
	public ArrayAdapter<String> getMainActionsAdapter(Context context){
		if (mainActionsAdapter == null){
			mainActionsAdapter = createMainActionsAdapter(context);
		}
		return mainActionsAdapter;
	}
	
	private static String[] tmpActions=null;
	private ArrayAdapter<String> createMainActionsAdapter(Context context) {
		tmpActions = new String[actions.length];
		for (int i=0; i<actions.length; ++i) {
			tmpActions[i] = actions[i];
		}
		tmpActions[actions.length-1] += " ("+pendingOrderList.size()+")";
		ArrayAdapter<String> aa = new ArrayAdapter<String>(context, android.R.layout.simple_list_item_1, tmpActions);
		return aa;
	}

	synchronized public void setCategories(List<Category> categories, String xml) {
		this.categories = new ArrayList<Category>();
		getCategories();
		
		try {
			FileOutputStream fos = signinContext.openFileOutput(CATEGORIES_XML,0);
			OutputStreamWriter out = new OutputStreamWriter(fos);  
			out.write(xml);  
			out.close();  
		} catch (FileNotFoundException fnfe) {
			Log.e(TAG, "Could not find " + CATEGORIES_XML + " file", fnfe);
		} catch (IOException ioe) {
			Log.e(TAG, "Could not write to " + CATEGORIES_XML + " file", ioe);
		}
	}

	@SuppressWarnings("unchecked")
	synchronized public List<Category> getCategories() {
		if (categories.size() == 0){
			Log.d(TAG, "reading categories from " + CATEGORIES_XML + "");
			try {
				FileInputStream fis = signinContext.openFileInput(CATEGORIES_XML);
				File f = new File(signinContext.getFilesDir()+"/"+CATEGORIES_XML);
				byte[] b = new byte[(int)f.length()];
				fis.read(b);
				String xml = new String(b);
				categories = (List<Category>) XStremUtil.toJava(xml);
				fis.close();
				
				id2ItemMap = new HashMap<Integer, Item>();
				for (Category category : categories) {
					for (Item item : category.getItems()) {
						id2ItemMap.put(item.getItemID(), item);
					}
				}
			} catch (FileNotFoundException fnfe) {
				Log.d(TAG, "could not find file: " + CATEGORIES_XML + "");
			} catch (IOException ioe){
				Log.e(TAG, "Could not read from " + CATEGORIES_XML + " file", ioe);
			}
		}
		return categories;
	}
	synchronized public Map<Integer, Item> getId2ItemMap() {
		if (id2ItemMap.size()==0){
			getCategories();
		}
		return id2ItemMap;
	}
	
	private String servername = null;
	synchronized public void setServername(String sn){
		this.servername = sn;
		try {
			FileOutputStream fos = signinContext.openFileOutput(SERVERNAME_XML,0);
			OutputStreamWriter out = new OutputStreamWriter(fos);  
			out.write(sn);  
			out.close();  
		} catch (FileNotFoundException fnfe) {
			Log.e(TAG, "Could not find " + SERVERNAME_XML + " file", fnfe);
		} catch (IOException ioe) {
			Log.e(TAG, "Could not write to " + SERVERNAME_XML + " file", ioe);
		}		
	}
	
	synchronized public String getServername(){
		if (servername == null){
			try{
				FileInputStream fis = signinContext.openFileInput(SERVERNAME_XML);
				File f = new File(signinContext.getFilesDir()+"/"+SERVERNAME_XML);
				byte[] b = new byte[(int)f.length()];
				fis.read(b);
				servername = new String(b);
				fis.close();				
			} catch (FileNotFoundException fnfe) {
				Log.d(TAG, "could not find file: " + SERVERNAME_XML + "");
			} catch (IOException ioe){
				Log.e(TAG, "Could not read from " + SERVERNAME_XML + " file", ioe);
			}
		}
		if (servername == null){
			servername = "10.0.0.2";
		}
		return servername;
	}
	
	synchronized public void setUsers(List<User> users, String xml) {
		this.users = users;
		try {
			FileOutputStream fos = signinContext.openFileOutput(USERS_XML,0);
			OutputStreamWriter out = new OutputStreamWriter(fos);  
			out.write(xml);  
			out.close();  
		} catch (FileNotFoundException fnfe) {
			Log.e(TAG, "Could not find " + USERS_XML + " file", fnfe);
		} catch (IOException ioe) {
			Log.e(TAG, "Could not write to " + USERS_XML + " file", ioe);
		}
	}
	@SuppressWarnings("unchecked")
	synchronized public List<User> getUsers() {
		if (users.size() == 0){
			Log.d(TAG, "reading users from " + USERS_XML + "");
			try {
				FileInputStream fis = signinContext.openFileInput(USERS_XML);
				File f = new File(signinContext.getFilesDir()+"/"+USERS_XML);
				byte[] b = new byte[(int)f.length()];
				fis.read(b);
				String xml = new String(b);
				users = (List<User>) XStremUtil.toJava(xml);
				fis.close();
				
			} catch (FileNotFoundException fnfe) {
				Log.d(TAG, "could not find file: " + USERS_XML + "");
			} catch (IOException ioe){
				Log.e(TAG, "Could not read from " + USERS_XML + " file", ioe);
			}
		}
		return users;
	}

	private List<User> users = new ArrayList<User>();
	private User loggedInUser= null;
	private List<Category> categories = new ArrayList<Category>();
	private Map<Integer, Item> id2ItemMap = new HashMap<Integer, Item>();
	
	public synchronized void addPendingOrder(Order pendingOrder){
		addPendingOrder(pendingOrderList.size(), pendingOrder);
	}
	public synchronized void addPendingOrder(int location, Order pendingOrder){
		if (pendingOrderList == null) {
			initPendingOrderList();			
		}
		pendingOrderList.add(location,pendingOrder);
		persistPendingOrders();

		tmpActions[actions.length-1] = actions[actions.length-1]+ " ("+pendingOrderList.size()+")";
		mainActionsAdapter = getMainActionsAdapter(mainActionsAdapter.getContext());
		mainActionsAdapter.notifyDataSetChanged();
		
		if (pendingOrderListAdaptor != null){
			pendingOrderListAdaptor.notifyDataSetChanged();
		}
	}
	
	public synchronized Order peekPendingOrder(int location){
		if (pendingOrderList == null) {
			initPendingOrderList();			
		}
		if (location >= pendingOrderList.size()){
			return null;
		}
		return pendingOrderList.get(location);	
	}
	public synchronized Order removePendingOrder(int location){
		Log.d("ucs", "+UCSData:removePendingOrder");
		if (pendingOrderList == null) {
			initPendingOrderList();			
		}
		if (location >= pendingOrderList.size()){
			return null;
		}
		Order pendingOrder = pendingOrderList.remove(location);
		persistPendingOrders();

//		Handler handler = new Handler()
		handler.post(new Runnable(){
			@Override
			public void run() {
				if (tmpActions != null){
					tmpActions[actions.length-1] = actions[actions.length-1]+" ("+pendingOrderList.size()+")";		
					mainActionsAdapter = getMainActionsAdapter(mainActionsAdapter.getContext());
					Log.d("ucs", "calling mainActionsAdapter.notifyDataSetChanged");
					mainActionsAdapter.notifyDataSetChanged();
				}
				if (pendingOrderListAdaptor != null){
					Log.d("ucs", "calling pendingOrderListAdaptor.notifyDataSetChanged");
					pendingOrderListAdaptor.notifyDataSetChanged();
				}
			}
		});
		Log.d("ucs", "-UCSData:removePendingOrder");
		return pendingOrder;
	}

	private void persistPendingOrders() {
		try {
			FileOutputStream fos = signinContext.openFileOutput(PENDING_ORDERS_XML,0);
			OutputStreamWriter out = new OutputStreamWriter(fos);  
			String xml = XStremUtil.toXML(pendingOrderList);
			out.write(xml);  
			out.close();  
		} catch (FileNotFoundException fnfe) {
			Log.e(TAG, "Could not find " + PENDING_ORDERS_XML+ " file", fnfe);
		} catch (IOException ioe) {
			Log.e(TAG, "Could not write to " + PENDING_ORDERS_XML+ " file", ioe);
		}
	}
	
	@SuppressWarnings("unchecked")
	private void initPendingOrderList(){
		try {
			FileInputStream fis = signinContext.openFileInput(PENDING_ORDERS_XML);
			File f = new File(signinContext.getFilesDir()+"/"+PENDING_ORDERS_XML);
			byte[] b = new byte[(int)f.length()];
			fis.read(b);
			fis.close();
			String xml = new String(b);
			pendingOrderList = (List<Order>) XStremUtil.toJava(xml);
			// removing the elements that is null
			while (true){
				boolean noNull = true;
				for (int i=0; i<pendingOrderList.size(); ++i){
					Order order = pendingOrderList.get(i);
					if (order == null){
						pendingOrderList.remove(i);
						noNull = false;
						break;
					}
				}
				if (noNull){
					break;
				}
			}
		} catch (FileNotFoundException fnfe) {
			pendingOrderList = new ArrayList<Order>();
		} catch (IOException ioe){
			Log.e(TAG, "Could not read from " + PENDING_ORDERS_XML+ " file", ioe);
		}		
	}

	private Handler handler;
	public void setContext(Context context) {
		handler = new Handler();
		this.signinContext = context;
		initPendingOrderList();
	}

	public synchronized void setLoggedInUser(User loggedInUser) {
		this.loggedInUser = loggedInUser;
	}

	public synchronized User getLoggedInUser() {
		return loggedInUser;
	}

}
